/*
 * RSAEncription.cpp
 *
 *  Created on: 12/11/2011
 *      Author: mario
 */

#include "RSAEncryption.h"
#include "RSAUtils.h"
#include "../../util/Utils.h"
#include "../log/Logger.h"
#include <math.h>

RSAEncryption *RSAEncryption::rsaInstance = NULL;

int RSAEncryption::phi(int a, int b)
{
	return (a - 1)*(b - 1);
}

int RSAEncryption::inverseMod(int phi, int d)
{
	int q,a1,a2,a3,b1,b2,b3;

	a1 = 1;
	a2 = 0;
	a3 = phi;
	b1 = 0;
	b2 = 1;
	b3 = d;

	do{
		q = a3/b3;
		int aux1 = a1;
		int aux2 = a2;
		int aux3 = a3;
		a1 = b1;
		a2 = b2;
		a3 = b3;

		b1 = aux1 - q*b1;
		b2 = aux2 - q*b2;
		b3 = aux3 - q*b3;

	}while(b3 != 1 && b3 != 0);

	if(b3 <= 0) {
		return -1;
	}

	return b2;
}

void RSAEncryption::initialize()
{
	do {
		this->p = RSAUtils::generatePrimeNumber();

			do {
				this->q = RSAUtils::generatePrimeNumber();
			}while (this->p == this->q);

			if( this->q > this->p) {
				int aux = this->p;
				this->p = this->q;
				this->q = aux;
			}

			this->n = this->p*this->q;

			long int phi = this->phi(this->p,this->q);

			do {
				this->d = Utils::random(7, 47);
			}while (this->d > phi && RSAUtils::gcd(phi, this->d));

			this->e = inverseMod(phi, this->d);

	}while(this->e <= 0);

	int y = 34;
	y++;
}

string getOriginalMsgCode(string msg)
{
	string msgCode = "";
	for (unsigned int i = 0; i < msg.size(); i++){
		int value = (int)msg[i];
		msgCode += Utils::intToString(value);
	}
	return msgCode;
}

string RSAEncryption::encrypt(string msg)
{
	Logger::createEntryLog("Encriptando Mensaje...",Logger::LOG);
	string finalMsg;

	for (unsigned int j = 0; j < msg.size(); j++){
		int value = (int)msg[j];
		string aux = Utils::intToString(expMod(value,this->e, this->n));
		finalMsg += aux;
		if(msg.size() != j+1){
			finalMsg += ";";
		}
	}
	Logger::createEntryLog("...Mensaje Encriptado: " + finalMsg,Logger::LOG);
	return finalMsg;
}



int RSAEncryption::expMod(int base, int exp, int mod)
{
	long r = 1;
	  while (exp > 0)
	    {
	      if ((exp & 1) > 0)
	    	  	  r = r * base % mod;
	      exp >>= 1;
	      base = (base * base) % mod;
	    }
	  return r;
}

long int RSAEncryption::getE() const
{
    return e;
}

long int RSAEncryption::getD() const
{
    return d;
}

long int RSAEncryption::getP() const
{
    return p;
}

long int RSAEncryption::getQ() const
{
    return q;
}

RSAEncryption *RSAEncryption::instance()
{
	if(!rsaInstance){
		rsaInstance = new RSAEncryption();
	}
	return rsaInstance;
}

RSAEncryption *RSAEncryption::newInstance()
{
	return new RSAEncryption();
}


int RSAEncryption::getN() const
{
    return n;
}

string RSAEncryption::decrypt(string msg)
{
	string msgCode = "";
	string partial = "";
	Logger::createEntryLog("Desencriptando Mensaje...",Logger::LOG);
	for (unsigned int i = 0; i < msg.length(); i++) {
		if ((char) msg[i] != ';') {
			partial += msg[i];
		} else {
			int code = expMod(Utils::stringToInt(partial), this->d, this->n);
			msgCode += static_cast<char>(code);

			partial = "";
		}
	}
	if (!partial.empty()) {
		int code = expMod(Utils::stringToInt(partial), this->d, this->n);
		msgCode += static_cast<char>(code);
	}
	Logger::createEntryLog("Mensaje Desencriptado...",Logger::LOG);
	return msgCode;
}




